summaryrefslogtreecommitdiff
path: root/app/[lng]
diff options
context:
space:
mode:
Diffstat (limited to 'app/[lng]')
-rw-r--r--app/[lng]/admin/mdg/page.tsx248
1 files changed, 248 insertions, 0 deletions
diff --git a/app/[lng]/admin/mdg/page.tsx b/app/[lng]/admin/mdg/page.tsx
new file mode 100644
index 00000000..27416f25
--- /dev/null
+++ b/app/[lng]/admin/mdg/page.tsx
@@ -0,0 +1,248 @@
+'use client'
+
+import { useState, useEffect } from 'react'
+import { Button } from '@/components/ui/button'
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Input } from '@/components/ui/input'
+import { Label } from '@/components/ui/label'
+import { Badge } from '@/components/ui/badge'
+import { toast } from 'sonner'
+import { Loader2, Send, RefreshCw } from 'lucide-react'
+
+// CSV 필드를 정의할 타입
+interface VendorFieldDef {
+ table: string;
+ name: string;
+ mandatory: boolean;
+ description: string;
+}
+
+// CSV 파싱 함수 (간단 파서)
+const parseCSV = (csv: string): VendorFieldDef[] => {
+ const lines = csv.trim().split('\n');
+ // 첫 번째 라인은 헤더이므로 제거
+ return lines.slice(1).map((line) => {
+ const parts = line.split(',');
+ const table = parts[1]?.trim();
+ const name = parts[2]?.trim();
+ const mandatory = parts[3]?.trim() === 'M';
+ const description = parts.slice(6).join(',').trim();
+ return { table, name, mandatory, description } as VendorFieldDef;
+ });
+};
+
+// 기존 샘플 기본값 (필요 시 확장)
+const sampleDefaults: Record<string, string> = {
+ BP_HEADER: 'TEST001',
+ ZZSRMCD: 'EVCP',
+ TITLE: 'TEST',
+ BU_SORT1: 'TEST VENDOR',
+ NAME_ORG1: '테스트 벤더 회사',
+ KTOKK: 'Z001',
+ VEN_KFBUS: '제조업',
+ VEN_KFIND: 'IT',
+ MASTERFLAG: 'X',
+ IBND_TYPE: 'U',
+ ZZREQID: 'TESTUSER01',
+ ADDRNO: '0001',
+ AD_NATION: '1',
+ COUNTRY: 'KR',
+ LANGU_COM: 'K',
+ POST_COD1: '06292',
+ CITY1: '서울시',
+ DISTRICT: '강남구',
+ REGION: '11',
+ MC_STREET: '테헤란로 123',
+ T_COUNTRY: 'KR',
+ T_NUMBER: '02-1234-5678',
+ F_COUNTRY: 'KR',
+ F_NUMBER: '02-1234-5679',
+ U_ADDRESS: 'https://test.vendor.com',
+ E_ADDRESS: 'contact@test.vendor.com',
+ BP_TX_TYP: 'KR2',
+ TAXNUM: '123-45-67890',
+};
+
+// XML escape helper
+const escapeXml = (unsafe: string) => unsafe.replace(/[<>&'"']/g, (c) => {
+ switch (c) {
+ case '<': return '&lt;';
+ case '>': return '&gt;';
+ case '&': return '&amp;';
+ case '"': return '&quot;';
+ case "'": return '&apos;';
+ default: return c;
+ }
+});
+
+export default function MDGTestPage() {
+ const [formData, setFormData] = useState<Record<string, string>>({});
+ const [fieldDefs, setFieldDefs] = useState<VendorFieldDef[]>([]);
+ const [resultXml, setResultXml] = useState<string>('');
+ const [isLoading, setIsLoading] = useState(false);
+
+ // CSV 로딩 및 초기 데이터 셋업
+ useEffect(() => {
+ const load = async () => {
+ const res = await fetch('/wsdl/P2MD3007_AO.csv');
+ const csvText = await res.text();
+ const defs = parseCSV(csvText);
+ setFieldDefs(defs);
+
+ const init: Record<string, string> = {};
+ defs.forEach((d) => {
+ init[d.name] = sampleDefaults[d.name] ?? '';
+ });
+ setFormData(init);
+ };
+
+ load();
+ }, []);
+
+ // 폼 데이터 업데이트
+ const updateField = (field: string, value: string) => {
+ setFormData(prev => ({ ...prev, [field]: value }));
+ };
+
+ // 기본값으로 리셋
+ const resetForm = () => {
+ const reset: Record<string, string> = {};
+ fieldDefs.forEach((d) => {
+ reset[d.name] = sampleDefaults[d.name] ?? '';
+ });
+ setFormData(reset);
+ toast.success('폼이 기본값으로 리셋되었습니다.');
+ };
+
+ // 테스트 송신 실행
+ const handleTestSend = async () => {
+ try {
+ setIsLoading(true);
+
+ // 필수 필드 검증
+ const requiredFields = fieldDefs.filter(d => d.mandatory).map(d => d.name);
+ const missingFields = requiredFields.filter(field => !formData[field]?.trim());
+
+ if (missingFields.length > 0) {
+ toast.error(`필수 필드가 누락되었습니다: ${missingFields.join(', ')}`);
+ return;
+ }
+
+ // XML 생성
+ const bodyContent = fieldDefs.map(f => {
+ const val = formData[f.name] ?? '';
+ return `<${f.name}>${escapeXml(val)}</${f.name}>`;
+ }).join('\n ');
+
+ const supplierXml = `<SUPPLIER_MASTER>\n ${bodyContent}\n </SUPPLIER_MASTER>`;
+
+ const envelope = `<?xml version="1.0" encoding="UTF-8"?>\n<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:p1=\"http://shi.samsung.co.kr/P2_MD/MDZ\">\n <soap:Header/>\n <soap:Body>\n <p1:MT_P2MD3007_S>\n <P2MD3007_S>\n ${supplierXml}\n </P2MD3007_S>\n </p1:MT_P2MD3007_S>\n </soap:Body>\n</soap:Envelope>`;
+
+ setResultXml(envelope);
+ toast.success('요청 XML이 생성되었습니다. 하단 영역을 확인하세요.');
+
+ } catch (error) {
+ console.error('테스트 송신 실패:', error);
+ toast.error('테스트 송신 중 오류가 발생했습니다.');
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+ <div className="container mx-auto p-6 space-y-6">
+ <div className="flex items-center justify-between">
+ <div>
+ <h1 className="text-3xl font-bold">MDG VENDOR 마스터 테스트</h1>
+ <p className="text-muted-foreground mt-2">
+ VENDOR 마스터 데이터를 MDG 시스템으로 테스트 송신합니다
+ </p>
+ </div>
+ <div className="flex gap-2">
+ <Button variant="outline" onClick={resetForm}>
+ <RefreshCw className="w-4 h-4 mr-2" />
+ 리셋
+ </Button>
+ <Button onClick={handleTestSend} disabled={isLoading}>
+ {isLoading ? (
+ <Loader2 className="w-4 h-4 mr-2 animate-spin" />
+ ) : (
+ <Send className="w-4 h-4 mr-2" />
+ )}
+ 테스트 송신
+ </Button>
+ </div>
+ </div>
+
+ {/* 동적 필드 렌더링 */}
+ {fieldDefs.length === 0 ? (
+ <p className="text-center text-muted-foreground">CSV 로딩 중...</p>
+ ) : (
+ <div className="space-y-6">
+ {Object.entries(
+ fieldDefs.reduce((acc: Record<string, VendorFieldDef[]>, cur) => {
+ acc[cur.table] = acc[cur.table] ? [...acc[cur.table], cur] : [cur];
+ return acc;
+ }, {})
+ ).map(([table, fields]) => (
+ <Card key={table}>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2">
+ {table}
+ {fields.some(f => f.mandatory) && (
+ <Badge variant="destructive">필수 포함</Badge>
+ )}
+ </CardTitle>
+ <CardDescription>{table} 테이블 입력</CardDescription>
+ </CardHeader>
+ <CardContent className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
+ {fields.filter((f, idx, arr) => arr.findIndex(x => x.name === f.name) === idx).map((field) => (
+ <div key={field.name}>
+ <Label htmlFor={field.name} className="flex items-center gap-1">
+ {field.name}
+ {field.mandatory && (
+ <Badge variant="destructive" className="ml-1">필수</Badge>
+ )}
+ </Label>
+ <Input
+ id={field.name}
+ value={formData[field.name] ?? ''}
+ onChange={(e) => updateField(field.name, e.target.value)}
+ />
+ {field.description && (
+ <p className="text-xs text-muted-foreground mt-1">{field.description}</p>
+ )}
+ </div>
+ ))}
+ </CardContent>
+ </Card>
+ ))}
+ </div>
+ )}
+
+ {/* 송신 결과 영역 */}
+ <Card>
+ <CardHeader>
+ <CardTitle>송신 결과</CardTitle>
+ <CardDescription>
+ MDG 시스템으로의 송신 결과가 여기에 표시됩니다
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ {resultXml ? (
+ <pre className="p-4 bg-muted max-h-96 overflow-auto text-xs whitespace-pre-wrap">
+ {resultXml}
+ </pre>
+ ) : (
+ <div className="p-4 bg-muted rounded-lg">
+ <p className="text-sm text-muted-foreground">
+ 테스트 송신 버튼을 클릭하면 결과가 표시됩니다.
+ </p>
+ </div>
+ )}
+ </CardContent>
+ </Card>
+ </div>
+ );
+}
+